package cn.edu.zut.score.service.impl;

import cn.edu.zut.score.core.cache.RedisCache;
import cn.edu.zut.score.core.constant.MessageTypeEnum;
import cn.edu.zut.score.core.constant.ReplyInfoStatus;
import cn.edu.zut.score.core.domain.PageResponse;
import cn.edu.zut.score.core.domain.RestResponse;
import cn.edu.zut.score.core.dto.request.ReplyInfoPageRequest;
import cn.edu.zut.score.core.dto.response.ReplyInfoResponse;
import cn.edu.zut.score.core.dto.response.ReplyResponse;
import cn.edu.zut.score.core.entity.*;
import cn.edu.zut.score.core.util.DateUtils;
import cn.edu.zut.score.mapper.ReplyInfoMapper;
import cn.edu.zut.score.service.*;
import cn.edu.zut.score.service.biz.WebSocketService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zby
 * @since 2021-06-25
 */
@Slf4j
@Service
public class ReplyInfoServiceImpl extends ServiceImpl<ReplyInfoMapper, ReplyInfo> implements IReplyInfoService {

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Autowired
    private RedisCache redisCache;

    @Autowired(required = false)
    private ReplyInfoMapper replyInfoMapper;

    @Autowired
    private IReplyService iReplyService;

    @Autowired
    private IUserService iUserService;

    @Autowired
    private IGroupInfoService iGroupInfoService;

    @Autowired
    private IMessageService iMessageService;

    @Autowired
    private IClazzService iClazzService;

    @Autowired
    private WebSocketService webSocketService;

    @Autowired
    private IGradeService iGradeService;

    @Override
    public RestResponse<List<Integer>> getDataById(Long replyid) {
        LambdaQueryWrapper<ReplyInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(ReplyInfo::getReplyId, replyid);
        List<ReplyInfo> replyInfos = replyInfoMapper.selectList(qw);
        List<Integer> res = new ArrayList<>();
        int sum = replyInfos.size();
        res.add(sum);
        Integer inline = sum - (int) replyInfos.stream().filter(replyInfo -> replyInfo.getStatus().equals(ReplyInfoStatus.noSign.getCode())).count();
        res.add(inline);
        Integer next = (int) replyInfos.stream().filter(replyInfo -> replyInfo.getStatus().equals(ReplyInfoStatus.over.getCode())).count() + 1;
        res.add(next);
        return RestResponse.success(res);
    }

    @Override
    public RestResponse<PageResponse<ReplyInfoResponse>> getListById(Long replyid, ReplyInfoPageRequest replyInfoPageRequest) {
        Reply reply = iReplyService.getById(replyid);
        if (reply == null) {
            return RestResponse.fail("答辩不存在");
        }
        Integer weight = reply.getWeight();
        log.info("ID为{}的答辩的学生打分权重为{}%", replyid, weight);
        Page<ReplyInfo> page = new Page<>(replyInfoPageRequest.getPage(), replyInfoPageRequest.getLimit());
        LambdaQueryWrapper<ReplyInfo> qw = new LambdaQueryWrapper<>();
        if (replyInfoPageRequest.getStatus() != -1) {
            qw.eq(ReplyInfo::getStatus, replyInfoPageRequest.getStatus());
        }
        qw.eq(ReplyInfo::getReplyId, replyid);
        qw.orderByAsc(ReplyInfo::getStatus, ReplyInfo::getId);
        IPage<ReplyInfo> pageData = replyInfoMapper.selectPage(page, qw);
        List<ReplyInfo> records = pageData.getRecords();
        List<ReplyInfoResponse> res = new ArrayList<>();
        for (ReplyInfo replyInfo : records) {
            ReplyInfoResponse response = new ReplyInfoResponse();
            User student = iUserService.getById(replyInfo.getStudentId());
            response.setStudentId(student.getId());
            response.setStudentNoId(student.getNoId());
            response.setStudentName(student.getName());
            response.setStatus(String.valueOf(replyInfo.getStatus()));
            response.setScore(iGradeService.getStudentSumScore(replyid, student.getId(), reply.getWeight()));
            res.add(response);
        }
        return RestResponse.success(new PageResponse<>(res, pageData.getTotal(), replyInfoPageRequest.getPage(), replyInfoPageRequest.getLimit()));
    }

    @Override
    public RestResponse<List<Integer>> getStuDataById(Long replyid) {
        String token = httpServletRequest.getHeader("Authorization");
        User currentUser = redisCache.getCurrentUser(token);
        Long studentId = currentUser.getId();
        LambdaQueryWrapper<ReplyInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(ReplyInfo::getReplyId, replyid);
        List<ReplyInfo> replyInfos = replyInfoMapper.selectList(qw);
        qw.eq(ReplyInfo::getStudentId, studentId);
        ReplyInfo replyInfo = replyInfoMapper.selectOne(qw);
        if (replyInfo == null) {
            return RestResponse.fail("答辩不存在");
        }
        List<Integer> res = new ArrayList<>();
        if (replyInfo.getStatus().equals(ReplyInfoStatus.over.getCode())) {
            log.info("用户{}已答辩", studentId);
            return RestResponse.success(res);
        }
        Integer inline = replyInfos.size() - (int) replyInfos.stream().filter(replyInfo1 -> replyInfo1.getStatus().equals(ReplyInfoStatus.noSign.getCode())).count();
        res.add(inline);
        if (replyInfo.getStatus().equals(ReplyInfoStatus.noSign.getCode())) {
            log.info("用户{}未报名", studentId);
            return RestResponse.success(res);
        }
        Integer next = (int) replyInfos.stream().filter(replyInfo2 -> replyInfo.getStatus().equals(ReplyInfoStatus.over.getCode())).count() + 1;
        res.add(next);
        return RestResponse.success(res);
    }

    @Override
    public RestResponse<ReplyResponse> inline(Long replyid) {
        Reply reply = iReplyService.getById(replyid);
        if (reply == null) {
            return RestResponse.fail("答辩不存在");
        }
        Date now = DateUtils.getCurrDate();
        if (now.getTime() < reply.getStartTime().getTime()) {
            return RestResponse.fail("答辩未开始");
        }
        if (now.getTime() > reply.getEndTime().getTime()) {
            return RestResponse.fail("答辩已结束");
        }

        String token = httpServletRequest.getHeader("Authorization");
        User currentUser = redisCache.getCurrentUser(token);
        Long studentId = currentUser.getId();
        ReplyInfo replyInfo = new ReplyInfo();
        replyInfo.setReplyId(replyid);
        replyInfo.setStudentId(studentId);
        replyInfo.setStatus(ReplyInfoStatus.inLine.getCode());
        replyInfo.fillUpdateInfo(httpServletRequest, redisCache);
        LambdaQueryWrapper<ReplyInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(ReplyInfo::getReplyId, replyid);
        qw.eq(ReplyInfo::getStudentId, studentId);
        this.update(replyInfo, qw);
        return RestResponse.success();
    }

    @Override
    public List<Long> getReplyUserIdsByReplyId(Long replyId, Long studentId) {
        Reply reply = iReplyService.getById(replyId);
        Long groupId = reply.getGroupId();
        LambdaQueryWrapper<GroupInfo> gqw = new LambdaQueryWrapper<>();
        gqw.eq(GroupInfo::getGroupId, groupId);
        List<Long> res = iGroupInfoService.list(gqw).stream().map(GroupInfo::getUserId).collect(Collectors.toList());
        if (reply.getWeight() != 0) {
            LambdaQueryWrapper<ReplyInfo> rqw = new LambdaQueryWrapper<>();
            rqw.eq(ReplyInfo::getReplyId, replyId);
            List<Long> studentIds = replyInfoMapper.selectList(rqw).stream().map(ReplyInfo::getStudentId).collect(Collectors.toList());
            if (reply.getSelfMark() == 0) {
                studentIds.remove(studentId);
            }
            res.addAll(studentIds);
        }
        return res;
    }

    @Override
    public RestResponse<String> remindInline(Long replyId) {
        Reply reply = iReplyService.getById(replyId);
        if (reply == null) {
            return RestResponse.fail("答辩不存在");
        }
        Date now = DateUtils.getCurrDate();
        if (now.getTime() < reply.getStartTime().getTime()) {
            return RestResponse.fail("答辩未开始");
        }
        if (now.getTime() > reply.getEndTime().getTime()) {
            return RestResponse.fail("答辩已结束");
        }
        LambdaQueryWrapper<ReplyInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(ReplyInfo::getReplyId, replyId);
        qw.eq(ReplyInfo::getStatus, ReplyInfoStatus.noSign.getCode());
        List<Long> studentIds = replyInfoMapper.selectList(qw).stream().map(ReplyInfo::getStudentId).collect(Collectors.toList());
        if (studentIds.size() == 0) {
            return RestResponse.fail("所有学生已预约答辩");
        }
        String title = "答辩预约提醒";
        String content = "您有一个答辩尚未预约，点击<a href=\"#/student/reply?replyId=" + replyId +
                "\" class=\"\" style=\"color: rgb(64, 158, 255);\"> 查看详情 </a>或在<a href=\"#/student/index\" " +
                "class=\"\" style=\"color: rgb(64, 158, 255);\"> 首页 </a>答辩列表点击进入查看，请及时查看并预约答辩、完成答辩。";
        iMessageService.addMessage(title, content, MessageTypeEnum.notice.getCode(), studentIds);

        webSocketService.sendOtherMessage(studentIds);
        return RestResponse.success("提醒成功");
    }

    @Override
    public RestResponse<String> beginReply(Long replyId, Long studentId) {
        Reply reply = iReplyService.getById(replyId);
        if (reply == null) {
            return RestResponse.fail("答辩不存在");
        }
        Date now = DateUtils.getCurrDate();
        if (now.getTime() < reply.getStartTime().getTime()) {
            return RestResponse.fail("答辩未开始");
        }
        if (now.getTime() > reply.getEndTime().getTime()) {
            return RestResponse.fail("答辩已结束");
        }
        LambdaQueryWrapper<ReplyInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(ReplyInfo::getReplyId, replyId);
        qw.eq(ReplyInfo::getStudentId, studentId);
        ReplyInfo replyInfo = new ReplyInfo();
        replyInfo.setStatus(ReplyInfoStatus.onGoning.getCode());
        replyInfo.fillUpdateInfo(httpServletRequest, redisCache);
        replyInfoMapper.update(replyInfo, qw);

        User student = iUserService.getById(studentId);
        Clazz clazz = iClazzService.getById(student.getClazzId());
        List<Long> receiveIds = getReplyUserIdsByReplyId(replyId, studentId);
        webSocketService.sendInfoMessage(clazz.getName(), student.getName(), receiveIds);

        return RestResponse.success("操作成功");
    }

    @Override
    public List<Long> getStudentIdsByReplyId(Long replyId) {
        LambdaQueryWrapper<ReplyInfo> qw = new LambdaQueryWrapper<>();
        qw.eq(ReplyInfo::getReplyId, replyId);
        qw.select(ReplyInfo::getStudentId);
        return replyInfoMapper.selectList(qw).stream().map(ReplyInfo::getStudentId).collect(Collectors.toList());
    }
}
